// 1.2.4.数组-相关-传递数组给函数
/**
 * C++ 支持数组数据结构，它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据，但它往往被认为是一系列相同类型的变量。
 * 数组的声明并不是声明一个个单独的变量，比如 number0、number1、...、number99，而是声明一个数组变量，比如 numbers，然后使用 numbers[0]、numbers[1]、...、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。
 * 所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素，最高的地址对应最后一个元素。
 * -----------------
 * 相关
 * 
 * 在 C++ 中，数组是非常重要的，我们需要了解更多有关数组的细节。下面列出了 C++ 程序员必须清楚的一些与数组相关的重要概念
 * 1.多维数组
 *  C++ 支持多维数组。多维数组最简单的形式是二维数组。
 * 2.指向数组的指针
 *  您可以通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。
 * 3.传递数组给函数
 *  您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。
 * 4.从函数返回数组
 *  C++ 允许从函数返回数组。
 * 
 * ~~~~~~~~~~~~~~~~~~
 * 传递数组给函数
 * C++ 中您可以通过指定不带索引的数组名来传递一个指向数组的指针。
 * C++ 传数组给一个函数，数组类型自动转换为指针类型，因而传的实际是地址。
 * 如果您想要在函数中传递一个一维数组作为参数，您必须以下面三种方式来声明函数形式参数，这三种声明方式的结果是一样的，因为每种方式都会告诉编译器将要接收一个整型指针。同样地，您也可以传递一个*多维数组*作为形式参数。
 *
 * 方式 1
 * 形式参数是一个指针：
    void myFunction(int *param)
    {
    .
    .
    .
    }
 * 
 * 方式 2
 * 形式参数是一个已定义大小的数组：
    void myFunction(int param[10])
    {
    .
    .
    .
    }
  *
  * 方式 3
  * 形式参数是一个未定义大小的数组：
    void myFunction(int param[])
    {
    .
    .
    .
    }
  *
  * 现在，让我们来看下面这个函数，它把数组作为参数，同时还传递了另一个参数，根据所传的参数，会返回数组中各元素的平均值：
  * 
  * 您可以看到，就函数而言，数组的长度是无关紧要的，因为 C++ 不会对形式参数执行边界检查。
*/

#include <iostream>
#include <iomanip>
double average_1(int *arr, int size);
double average_2(int[5], int);
double average_3(int[], int);

void array_more_dim(int **arr);
// void array_more_dim(int arr[3][2]);
// void array_more_dim(int arr[][2]);
int main(void)
{
  int num[5] = {2, 4, 6, 8, 10};

  std::cout << "sizeof(num) : " << sizeof(num) << std::endl;
  std::cout << "sizeof(int) : " << sizeof(int) << std::endl;
  std::cout << "num length : " << sizeof(num) / sizeof(int) << std::endl;
  // double val = average_1(num, 5);
  // double val = average_2(num, 5);
  // double val = average_3(num, 5);
  int *ptr;
  ptr = num;
  // double val = average_3(ptr, 5);
  // double val = average_1(&num[0], 5);
  double val = average_2(&num[0], 5);
  // double val = average_3(&num[0], 5);

  // double val = average_3((int[]){2, 4, 6, 8, 10}, 5); // error: taking address of temporary array
  std::cout << "val : " << val << std::endl;

  int nums[][2] = {
      {1, 2},
      {2, 3},
      {3, 4}};

  // array_more_dim(nums); // 这样有问题
  array_more_dim((int **)nums);
  // array_more_dim(nums);

  printf("---------end----------\n");
  return 0;
}

// 方式一、形式参数是一个指针
double average_1(int *arr, int size)
{
  int total = 0;
  int i = 0;

  std::cout << "sizeof(arr) : " << sizeof(arr) << std::endl;

  for (i = 0; i < size; i++)
  {
    // total += *(arr + i);
    total += arr[i];
  }
  return (double)total / size;
}

// 方式二是一个已定义大小的数组
double average_2(int arr[5], int size)
{
  std::cout << "sizeof(arr) : " << sizeof(arr) << std::endl; // 2
  int total = 0;
  for (int i = 0; i < size; i++)
  {
    total += arr[i];
  }
  return (double)total / size;
}

// 方式三是一个未定义大小的数组
double average_3(int arr[], int size)
{
  std::cout << "sizeof(arr) : " << sizeof(arr) << std::endl; // 2
  int total = 0;
  for (int i = 0; i < size; i++)
  {
    total += arr[i];
  }
  return (double)total / size;
}

void array_more_dim(int **arr)
{
  //  *((int *)num+5*i+j)         //这样可以
  //  ((int *)num+5*i)[j]         //这样可以
  //  num[i][j]" ";                   //这样不可以
  // ***多维的数组大小还是要知道才好处理
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 2; j++)
    {
      // std::cout << "arr[" << i << "][" << j << "]" << arr[i][j] << std::endl; // 这样写是错误的

      std::cout << "arr[" << i << "][" << j << "]" << *((int *)arr + 2 * i + j) << std::endl;
      // std::cout << "arr[" << i << "][" << j << "]" << ((int *)arr + 2 * i)[j] << std::endl;
    }
  }
}

// error declaration of 'arr' as multidimensional array must have bounds for all dimensions
// 将“arr”声明为多维数组必须具有所有维度的边界
// int arr[3][2]
// int arr[][2] 两种方式都行
void array_more_dim(int arr[][2])
{

  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 2; j++)
    {
      // std::cout << "arr[" << i << "][" << j << "]" << arr[i][j] << std::endl;

      // std::cout << "arr[" << i << "][" << j << "]" << *((int *)arr + 2 * i + j) << std::endl;
      std::cout << "arr[" << i << "][" << j << "]" << ((int *)arr + 2 * i)[j] << std::endl;
    }
  }
}